# -*- coding: utf-8 -*-

import sys
import time
from PyQt5 import QtWidgets
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QApplication, QMainWindow
import PyQt5.QtGui as qg
from qthread_example_ui import Ui_Form
from xml.dom.minidom import parseString
import re
import appico
import socket
import struct

dev_list = {}

# Pyinstaller -F -w -i scan.ico test.py
class MyMainForm(QMainWindow, Ui_Form):
    def __init__(self, parent=None):
        super(MyMainForm, self).__init__(parent)
        self.setupUi(self)
        self.setWindowTitle(' 局域网设备发现工具 V1.1 ')
        self.setWindowIcon(qg.QIcon(':pic/scan.ico'))
        # 实例化线程对象
        self.work_thread = scanThread("234.10.10.100", 60000, 1)
        self.work_thread1 = scanThread("234.10.10.100", 20000, 0)
        self.runButton.clicked.connect(self.execute)

        self.tableWidget.setColumnWidth(0, 100)
        self.tableWidget.setColumnWidth(1, 125)
        self.tableWidget.setColumnWidth(2, 60)
        self.tableWidget.setColumnWidth(3, 120)  # 设置table表格第4列的宽度，130为宽度
        self.tableWidget.setColumnWidth(4, 135)
        self.tableWidget.setColumnWidth(5, 220)
        self.tableWidget.verticalHeader().setHidden(True)

        self.bStart = False
        self.work_thread.signal.connect(self.display)
        self.work_thread1.signal.connect(self.display)

    def execute(self):
        if self.bStart == False:
            self.bStart = True
            self.runButton.setText('Stop')
            self.work_thread.start()
            self.work_thread1.start()

        else:
            self.bStart = False
            self.runButton.setText('Run')
            self.work_thread.stop()
            self.work_thread1.stop()
        # print('t:',self.work_thread.is_alive())
        # 启动线程

        # 线程自定义信号连接的槽函数


    def display(self,m_dict):
        # 由于自定义信号时自动传递一个字符串参数，所以在这个槽函数中要接受一个参数
        find = False
        k, v = m_dict.popitem()
        for key in dev_list.keys():
            if key == k:
                find = True

        if find == False:
            dev_list.update({k:v})
            # msg="设备IP:"+str(k)+"   "+str(v)
            # self.listWidget.addItem(msg)
            row = self.tableWidget.rowCount()
            self.tableWidget.insertRow(row)
            item = QtWidgets.QTableWidgetItem(str(k))
            self.tableWidget.setItem(row, 0, item)
            i=1
            for m in v:
                item = QtWidgets.QTableWidgetItem(m)
                self.tableWidget.setItem(row, i, item)
                i+=1

class scanThread(QThread):
    # 自定义信号对象。参数str就代表这个信号可以传一个字符串
    signal = pyqtSignal(dict)
    def __init__(self, ip, port, type):
        # 初始化函数
        super(scanThread, self).__init__()
        self.ip=ip
        self.port=port
        self.type=type

    def stop(self):
        self.terminate()

    def run(self):
        if self.type == 0:
            self.recv_udp_broadcast()
        elif self.type == 1:
            self.recv_udp_broadcast1()

    def get_host_ip(self):
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.connect(('8.8.8.8', 80))
            ip = s.getsockname()[0]
        finally:
            s.close()
        return ip

    def creat_socket(self):
        if "linux" in sys.platform:
            # 绑定到的网卡名，如果自己的不是eth0则注意修改
            nic_name = "eth0"
            # 监听的组播地址
            host_ip = "239.255.255.252"
        else:
            host_ip = self.get_host_ip()
        print(host_ip)

        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind((host_ip, self.port))
        s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
        s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 0)
        # s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, SOCKET_BUFSIZE)
        # mreq = struct.pack("=4sl", socket.inet_aton(MULTICAST_IP), socket.inet_aton(m_ip))
        s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(self.ip) + socket.inet_aton(host_ip))
        # s.setblocking(1)
        return s

    def recv_udp_broadcast(self):
        s = self.creat_socket()
        while True:
            try:
                recv_data = s.recvfrom(1024)
            except :
                print("while receive message error occur")
            else:
                recv_msg = recv_data[0]
                send_addr = recv_data[1]
                data = struct.unpack('1c64s1cH', recv_msg[0:68])
                source_ip =  send_addr[0]
                # print("信息来自：%s 内容是：%s" % (str(send_addr), recv_msg.decode("utf-8")))
                # print("信息来自：%s 内容是：%s" % (str(send_addr), recv_msg[68:].decode("utf-8")))
                text = re.sub(u"[\x00-\x08\x0b-\x0c\x0e-\x1f]+", u"", recv_msg[68:].decode("utf-8"))
                result = self.read_xml(text)
                if result == False:
                    continue
                self.signal.emit({source_ip:result})

    def read_xml(self,str):
        domTree = parseString (str)
        rootNode = domTree.documentElement
        deviceNodes = rootNode.getElementsByTagName("DEVICE")
        if deviceNodes.length == 0:
            return False
        id = deviceNodes[0].getAttribute("ID")
        name = deviceNodes[0].getAttribute("NAME")
        hver = deviceNodes[0].getAttribute("HVER")
        sver = deviceNodes[0].getAttribute("SVER")
        type = deviceNodes[0].getAttribute("TYPE")
        model = deviceNodes[0].getAttribute("Model")
        return id, type, model, sver, hver

    def read_xml1(self,str):
        domTree = parseString (str)
        rootNode = domTree.documentElement
        # deviceNodes = rootNode.getElementsByTagName("MESSAGE")
        if rootNode.hasAttribute("SERIALNO"):
            pass
        else:
            return False
        id = rootNode.getAttribute("SERIALNO")
        name = ""#deviceNodes[0].getAttribute("NAME")
        hver = ""#deviceNodes[0].getAttribute("HVER")
        sver = ""#deviceNodes[0].getAttribute("SVER")
        type = rootNode.getAttribute("DEVTYPE")
        model = "dsw-gateway"#deviceNodes[0].getAttribute("Model")
        return id, type, model, sver, hver

    def recv_udp_broadcast1(self):
        s = self.creat_socket()
        while True:
            try:
                recv_data = s.recvfrom(1024)
            except :
                print("while receive message error occur")
            else:
                recv_msg = recv_data[0]
                send_addr = recv_data[1]
                source_ip =  send_addr[0]
                print("信息来自：%s 内容是：%s" % (str(send_addr), recv_msg.decode("utf-8")))
                text = re.sub(u"[\x00-\x08\x0b-\x0c\x0e-\x1f]+", u"", recv_msg.decode("utf-8"))
                result = self.read_xml1(text)
                if result == False:
                    continue
                self.signal.emit({source_ip:result})

if __name__ == "__main__":
    app = QApplication(sys.argv)
    myWin = MyMainForm()
    myWin.show()
    sys.exit(app.exec_())